<template>
  <div class="dashboard-container">
    <header>
      <router-link to="/adminLayout" class="home-link">
        <i class="el-icon-s-home"></i> 首页
      </router-link>
      <h1>灵医疗数据可视化平台</h1>
      <div class="showTime">
        <span>{{ currentTime }}</span>
      </div>
    </header>

    <div class="main-content">
      <!-- 两列布局 -->
      <div class="two-column-layout">
        <!-- 左侧列 -->
        <div class="left-column">
          <!-- 近20天挂号人数趋势 -->
          <div class="panel">
            <h2>近20天挂号人数趋势</h2>
            <div class="chart" ref="orderPeopleChart"></div>
          </div>

          <!-- 医生评分词云 -->
          <div class="panel">
            <h2>医生平均评分</h2>
            <div class="chart" ref="doctorRatingChart"></div>
          </div>

          <!-- 患者年龄段分布 -->
          <div class="panel">
            <h2>患者年龄段分布</h2>
            <div class="chart" ref="patientAgeChart"></div>
          </div>
        </div>

        <!-- 右侧列 -->
        <div class="right-column">
          <!-- 今日数据卡片 -->
          <div class="panel today-data-panel">
            <div class="today-data-card">
              <div class="data-card">
                <h3>今日预约挂号</h3>
                <div class="data-value">{{ todayOrderCount }}</div>
              </div>
              <div class="data-card">
                <h3>今日住院人数</h3>
                <div class="data-value">{{ todayBedCount }}</div>
              </div>
            </div>
          </div>

          <!-- 科室挂号量统计 -->
          <div class="panel">
            <h2>科室挂号量统计</h2>
            <div class="chart" ref="orderSectionChart"></div>
          </div>

          <!-- 药物库存表格 -->
          <div class="panel drug-table-panel">
            <h2>药物库存情况</h2>
            <div class="drug-table-container" ref="drugTableContainer">
              <table class="drug-table">
                <thead>
                  <tr>
                    <th>药品名称</th>
                    <th>剩余数量</th>
                    <th>单价(元)</th>
                    <th>生产厂商</th>
                  </tr>
                </thead>
                <tbody>
                  <tr v-for="drug in drugList" :key="drug.drugId" :class="{ 'low-stock-warning': drug.drNumber < 20 }">
                    <td><span v-if="drug.drNumber < 20" class="warning-icon">⚠️</span>{{ drug.drName }}</td>
                    <td>{{ drug.drNumber }}</td>
                    <td>{{ drug.drPrice }}</td>
                    <td>{{ drug.drPublisher }}</td>
                  </tr>
                </tbody>
              </table>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import request from "@/utils/request.js";
import { debounce } from "lodash";
import * as echarts from "echarts";

export default {
  name: "medicalDashboard",
  data() {
    return {
      sevenDate: [],
      currentTime: "",
      currentDate: "",
      timer: null,
      resizeObserver: null,
      charts: {
        orderPeople: null,
        orderSection: null,
        doctorRating: null,
        patientAge: null,
      },
      ageGroups: [
        "0-9岁",
        "10-19岁",
        "20-29岁",
        "30-39岁",
        "40-49岁",
        "50-59岁",
        "60-69岁",
        "70-79岁",
        "80-89岁",
        "90-99岁",
      ],
      todayOrderCount: 0,
      todayBedCount: 0,
      drugList: [],
      scrollInterval: null,
    };
  },
  mounted() {
    this.updateTime();
    this.timer = setInterval(this.updateTime, 1000);
    this.initCharts();
    this.setupResizeObserver();
    this.loadTodayData();
    this.loadDrugData();
    this.startTableScroll();
  },
  beforeDestroy() {
    this.stopTableScroll();
    clearInterval(this.timer);
    clearInterval(this.scrollInterval);
    if (this.resizeObserver) {
      this.resizeObserver.disconnect();
    }
    Object.values(this.charts).forEach((chart) => {
      if (chart) chart.dispose();
    });
  },
  methods: {
    updateTime() {
      const dt = new Date();
      this.currentDate = `${dt.getFullYear()}-${(dt.getMonth() + 1)
        .toString()
        .padStart(2, "0")}-${dt.getDate().toString().padStart(2, "0")}`;
      this.currentTime = `${this.currentDate} ${dt
        .getHours()
        .toString()
        .padStart(2, "0")}:${dt.getMinutes().toString().padStart(2, "0")}:${dt
        .getSeconds()
        .toString()
        .padStart(2, "0")}`;
    },

    setupResizeObserver() {
      this.resizeObserver = new ResizeObserver(
        debounce(() => {
          this.resizeAllCharts();
        }, 100)
      );

      const chartRefs = [
        "orderPeopleChart",
        "orderSectionChart",
        "doctorRatingChart",
        "patientAgeChart",
      ];

      chartRefs.forEach((key) => {
        const el = this.$refs[key];
        if (el) this.resizeObserver.observe(el.parentElement);
      });
    },

    resizeAllCharts() {
      Object.values(this.charts).forEach((chart) => {
        if (chart) {
          chart.resize({
            animation: {
              duration: 300,
            },
          });
        }
      });
    },

    initCharts() {
      this.charts.orderPeople = echarts.init(this.$refs.orderPeopleChart);
      this.charts.orderSection = echarts.init(this.$refs.orderSectionChart);
      this.charts.doctorRating = echarts.init(this.$refs.doctorRatingChart);
      this.charts.patientAge = echarts.init(this.$refs.patientAgeChart);

      this.loadAllChartData();
    },

    async loadAllChartData() {
      try {
        await Promise.all([
          this.loadOrderPeopleData(),
          this.loadOrderSectionData(),
          this.loadDoctorRatingData(),
          this.loadPatientAgeData(),
        ]);
        this.$nextTick(() => {
          this.resizeAllCharts();
        });
      } catch (error) {
        console.error("图表数据加载失败:", error);
      }
    },

    async loadOrderPeopleData() {
      const res = await request.get("order/orderSeven");
      if (res.data.status !== 200) throw new Error("数据请求失败");

      const option = {
        tooltip: {
          trigger: "axis",
          axisPointer: {
            type: "cross",
            label: {
              backgroundColor: "#6a7985",
            },
          },
        },
        grid: {
          left: "3%",
          right: "4%",
          bottom: "3%",
          containLabel: true,
        },
        xAxis: {
          type: "category",
          boundaryGap: false,
          data: this.sevenDate,
          axisLabel: {
            color: "#81E7ED",
          },
          axisLine: {
            lineStyle: {
              color: "rgba(129, 231, 237, 0.3)",
            },
          },
        },
        yAxis: {
          type: "value",
          axisLabel: {
            color: "#81E7ED",
          },
          axisLine: {
            lineStyle: {
              color: "rgba(129, 231, 237, 0.3)",
            },
          },
          splitLine: {
            lineStyle: {
              color: "rgba(129, 231, 237, 0.1)",
            },
          },
        },
        series: [
          {
            name: "挂号人数",
            type: "line",
            smooth: false, // 关闭平滑效果
            lineStyle: {
              width: 2, // 线宽可以适当减小
              color: "#02a6b5", // 使用单一颜色而不是渐变
            },
            showSymbol: true, // 显示数据点
            symbol: "circle", // 数据点形状
            symbolSize: 6, // 数据点大小
            itemStyle: {
              color: "#02a6b5", // 数据点颜色
            },
            areaStyle: {
              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                { offset: 0, color: "rgba(2, 166, 181, 0.3)" },
                { offset: 1, color: "rgba(2, 166, 181, 0.1)" },
              ]),
            },
            data: res.data.data,
          },
        ],
      };

      this.charts.orderPeople.setOption(option);
    },

    async loadOrderSectionData() {
      const res = await request.get("order/orderSection");
      const option = {
        tooltip: {
          trigger: "axis",
          axisPointer: {
            type: "shadow",
          },
        },
        grid: {
          left: "3%",
          right: "4%",
          bottom: "12%",
          containLabel: true,
        },
        xAxis: {
          type: "category",
          data: res.data.data.map((item) => item.doctor.dSection),
          axisLabel: {
            interval: 0,
            rotate: 30,
            color: "#81E7ED",
          },
          axisLine: {
            lineStyle: {
              color: "rgba(129, 231, 237, 0.3)",
            },
          },
        },
        yAxis: {
          type: "value",
          axisLabel: {
            color: "#81E7ED",
          },
          axisLine: {
            lineStyle: {
              color: "rgba(129, 231, 237, 0.3)",
            },
          },
          splitLine: {
            lineStyle: {
              color: "rgba(129, 231, 237, 0.1)",
            },
          },
        },
        series: [
          {
            name: "挂号量",
            data: res.data.data.map((item) => item.countSection),
            type: "bar",
            barWidth: "60%",
            itemStyle: {
              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                { offset: 0, color: "#02a6b5" },
                { offset: 1, color: "#4EDC9E" },
              ]),
              borderRadius: [4, 4, 0, 0],
            },
          },
        ],
      };

      this.charts.orderSection.setOption(option);
    },

    async loadDoctorRatingData() {
      try {
        const res = await request.get("admin/findAll");
        if (res.data.status !== 200) throw new Error("数据请求失败");

        const doctorData = res.data.data.map((doctor) => ({
          name: doctor.dName,
          value: doctor.dAvgStar || 0,
          rating: doctor.dAvgStar || 0,
          itemStyle: {
            color: this.getColorByRating(doctor.dAvgStar),
          },
        }));

        const option = {
          tooltip: {
            trigger: "item",
            formatter: (params) => {
              return `
              <div style="font-weight:bold">${params.name}</div>
              平均评分: ${params.data.rating.toFixed(1)}<br/>
            `;
            },
          },
          series: [
            {
              type: "wordCloud",
              shape: "circle",
              left: "center",
              top: "center",
              width: "90%",
              height: "90%",
              sizeRange: [12, 60],
              rotationRange: [-45, 45],
              rotationStep: 15,
              gridSize: 8,
              drawOutOfBound: false,
              textStyle: {
                fontFamily: "Microsoft YaHei",
                fontWeight: "bold",
                color: function () {
                  return (
                    "rgb(" +
                    Math.round(Math.random() * 155 + 100) +
                    "," +
                    Math.round(Math.random() * 155 + 100) +
                    "," +
                    Math.round(Math.random() * 155 + 100) +
                    ")"
                  );
                },
              },
              emphasis: {
                textStyle: {
                  shadowBlur: 10,
                  shadowColor: "#4EDC9E",
                },
              },
              data: doctorData,
            },
          ],
        };

        this.charts.doctorRating.setOption(option);
      } catch (error) {
        console.error("加载医生评分数据失败:", error);
        this.$message.error("医生评分数据加载失败");
      }
    },

    getColorByRating(rating) {
      if (!rating) return "#999";
      if (rating >= 4.5) return "#4EDC9E";
      if (rating >= 4.0) return "#4EA6DC";
      if (rating >= 3.0) return "#DCD14E";
      return "#DC4E4E";
    },

    async loadPatientAgeData() {
      try {
        const res = await request.get("patient/patientAge");
        const ageData = this.ageGroups.map((ageGroup, index) => ({
          name: ageGroup,
          value: res.data.data[index] || 0,
          symbolSize: Math.max(20, (res.data.data[index] || 0) / 5),
        }));
        const option = {
          tooltip: {
            trigger: "item",
            formatter: "{a}<br/>{b}: {c}人",
          },
          grid: {
            top: 50,
            bottom: 20,
            containLabel: true,
          },
          xAxis: {
            type: "category",
            data: this.ageGroups,
            axisLabel: {
              color: "#81E7ED",
            },
            axisLine: { lineStyle: { color: "rgba(129, 231, 237, 0.3)" } },
          },
          yAxis: {
            type: "value",
            minInterval: 1,
            axisLabel: {
              color: "#81E7ED",
              formatter: function (value) {
                return Math.floor(value);
              },
            },
            axisLine: { lineStyle: { color: "rgba(129, 231, 237, 0.3)" } },
            splitLine: { lineStyle: { color: "rgba(129, 231, 237, 0.1)" } },
          },
          series: [
            {
              name: "患者人数",
              type: "scatter",
              data: ageData,
              itemStyle: {
                color: (params) =>
                  [
                    "#4EA6DC",
                    "#4EDC9E",
                    "#DC4E4E",
                    "#DCD14E",
                    "#9E4EDC",
                    "#4E8BDC",
                    "#4EDCB5",
                    "#DC7A4E",
                    "#4EDC7A",
                    "#B54EDC",
                  ][params.dataIndex % 10],
              },
            },
          ],
        };

        this.charts.patientAge.setOption(option);
      } catch (error) {
        console.error("加载数据失败:", error);
        this.$message.error("数据加载失败");
      }
    },

    async loadTodayData() {
      try {
        const [orderRes, bedRes] = await Promise.all([
          request.get("order/orderPeople"),
          request.get("bed/bedPeople"),
        ]);

        if (orderRes.data.status === 200) {
          this.todayOrderCount = orderRes.data.data;
        }

        if (bedRes.data.status === 200) {
          this.todayBedCount = bedRes.data.data;
        }
      } catch (error) {
        console.error("加载今日数据失败:", error);
      }
    },

    async loadDrugData() {
      try {
        const res = await request.get("drug/findAllDrugsWithoutPage");
        if (res.data.status === 200) {
          this.drugList = res.data.data;
          this.$nextTick(() => {
            this.startTableScroll();
          });
        }
      } catch (error) {
        console.error("加载药品数据失败:", error);
      }
    },

    startTableScroll() {
      this.stopTableScroll();

      const container = this.$refs.drugTableContainer;
      if (!container || this.drugList.length <= 5) return;

      let scrollPosition = 0;
      const scrollStep = 1;
      const scrollSpeed = 30;
      const pauseDuration = 2000;
      let isPaused = false;

      this.scrollInterval = setInterval(() => {
        if (isPaused) return;

        const maxScroll = container.scrollHeight - container.clientHeight;
        scrollPosition += scrollStep;

        if (scrollPosition >= maxScroll) {
          isPaused = true;
          setTimeout(() => {
            this.smoothScrollToTop(container, () => {
              scrollPosition = 0;
              isPaused = false;
            });
          }, pauseDuration);
        } else {
          container.scrollTop = scrollPosition;
        }
      }, scrollSpeed);
    },

    smoothScrollToTop(element, callback) {
      const start = element.scrollTop;
      const change = -start;
      const duration = 500;
      let startTime = null;

      const animateScroll = (timestamp) => {
        if (!startTime) startTime = timestamp;
        const elapsed = timestamp - startTime;
        const progress = Math.min(elapsed / duration, 1);
        const easeInOut =
          progress < 0.5
            ? 2 * progress * progress
            : 1 - Math.pow(-2 * progress + 2, 2) / 2;

        element.scrollTop = start + change * easeInOut;

        if (progress < 1) {
          requestAnimationFrame(animateScroll);
        } else if (callback) {
          callback();
        }
      };

      requestAnimationFrame(animateScroll);
    },

    stopTableScroll() {
      if (this.scrollInterval) {
        clearInterval(this.scrollInterval);
        this.scrollInterval = null;
      }
    },

    pastSeven(num) {
      const date = new Date();
      date.setDate(date.getDate() - num);
      return `${date.getMonth() + 1}-${date.getDate()}`;
    },
  },
  created() {
    this.sevenDate = Array.from({ length: 21 }, (_, i) =>
      this.pastSeven(10 - i)
    );
  },
};
</script>

<style scoped>
.dashboard-container {
  width: 100%;
  min-height: 100vh;
  font-family: "Microsoft YaHei", Arial, sans-serif;
  background-color: #06164a;
  color: white;
  display: flex;
  flex-direction: column;
  padding: 15px;
}

header {
  position: relative;
  height: 60px;
  display: flex;
  justify-content: center;
  align-items: center;
}

.home-link {
  position: absolute;
  left: 30px;
  color: #81e7ed;
  text-decoration: none;
  font-size: 16px;
  display: flex;
  align-items: center;
  transition: all 0.3s;
}

.home-link i {
  margin-right: 5px;
  font-size: 18px;
}

.home-link:hover {
  color: #4edc9e;
  text-shadow: 0 0 5px rgba(129, 231, 237, 0.5);
}

header h1 {
  font-size: 36px;
  color: #81e7ed;
  text-shadow: 0 0 10px rgba(129, 231, 237, 0.5);
}

.showTime {
  position: absolute;
  right: 30px;
  font-size: 16px;
  color: #81e7ed;
}

.main-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.two-column-layout {
  display: flex;
  gap: 20px;
  flex: 1;
  min-height: 0;
}

.left-column,
.right-column {
  display: flex;
  flex-direction: column;
  gap: 20px;
  flex: 1;
  min-height: 0;
}

.panel {
  border: 1px solid rgba(25, 186, 139, 0.17);
  background: rgba(255, 255, 255, 0.04);
  padding: 15px;
  border-radius: 5px;
  display: flex;
  flex-direction: column;
  min-height: 0;
  position: relative;
}

.panel::before,
.panel::after {
  content: "";
  position: absolute;
  width: 10px;
  height: 10px;
  border-radius: 20%;
}

.panel::before {
  top: 0;
  left: 0;
  border-top: 2px solid #02a6b5;
  border-left: 2px solid #02a6b5;
}

.panel::after {
  top: 0;
  right: 0;
  border-top: 2px solid #02a6b5;
  border-right: 2px solid #02a6b5;
}

.panel h2 {
  font-size: 18px;
  color: #81e7ed;
  text-align: center;
  margin-bottom: 15px;
}

.chart {
  flex: 1;
  width: 100%;
  min-height: 300px;
}

.today-data-panel {
  min-height: auto;
}

.today-data-card {
  display: flex;
  justify-content: space-around;
  gap: 20px;
  padding: 10px;
}

.data-card {
  flex: 1;
  background: rgba(129, 231, 237, 0.1);
  border-radius: 8px;
  padding: 15px;
  text-align: center;
  border: 1px solid rgba(129, 231, 237, 0.3);
}

.data-card h3 {
  font-size: 16px;
  color: #81e7ed;
  margin-bottom: 10px;
}

.data-value {
  font-size: 28px;
  font-weight: bold;
  color: #4edc9e;
}

.drug-table-panel {
  flex: 1;
}

.drug-table-container {
  flex: 1;
  overflow: hidden;
  position: relative;
  max-height: 500px;
  display: flex;
  flex-direction: column;
}

.drug-table {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}

.drug-table th,
.drug-table td {
  padding: 12px 15px;
  text-align: left;
  border-bottom: 1px solid rgba(129, 231, 237, 0.2);
  color: #81e7ed;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.drug-table th {
  background-color: rgba(2, 166, 181, 1);
  font-weight: bold;
  position: sticky;
  top: 0;
  z-index: 1;
}

.drug-table tbody tr:hover {
  background-color: rgba(129, 231, 237, 0.1);
}

.drug-table th:nth-child(1),
.drug-table td:nth-child(1) {
  width: 30%;
}

.drug-table th:nth-child(2),
.drug-table td:nth-child(2) {
  width: 20%;
  text-align: right;
}

.drug-table th:nth-child(3),
.drug-table td:nth-child(3) {
  width: 20%;
  text-align: right;
}

.drug-table th:nth-child(4),
.drug-table td:nth-child(4) {
  width: 30%;
}

.low-stock-warning {
  background-color:#e74c3c;
}

.warning-icon {
  color: #e74c3c;
  margin-left: 5px;
  font-size: 14px;
}
@keyframes flash {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

.low-stock-warning {
  animation: flash 1s infinite; /* 2秒闪烁一次 */
}
@media (max-width: 1200px) {
  .two-column-layout {
    flex-direction: column;
  }

  .today-data-card {
    flex-direction: column;
  }
}
</style>